package com.kokotchy.tuxcontrol;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.GestureDetector;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.kokotchy.tuxcontrol.provider.MessageList;
import com.kokotchy.tuxcontrol.provider.MessageList.Messages;

/**
 * Main activity
 * 
 * $Date: 2009-12-30 15:09:35 +0000 (Wed, 30 Dec 2009) $
 * 
 * @author $Author: kokotchy $
 * @version $Revision: 18 $
 * 
 */
public class Tux extends Activity {

	/**
	 * Gesture listener for making Tux spin
	 * 
	 * $Date: 2009-12-30 15:09:35 +0000 (Wed, 30 Dec 2009) $
	 * 
	 * @author $Author: kokotchy $
	 * @version $Revision: 18 $
	 * 
	 */
	class MyGestureBottomListener extends
			GestureDetector.SimpleOnGestureListener {

		@Override
		public boolean onDown(MotionEvent e) {
			return true;
		}

		@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
				float velocityY) {
			float x1 = e1.getX();
			float y1 = e1.getY();
			float x2 = e2.getX();
			float y2 = e2.getY();

			float fysens = y2 - y1;
			float fxsens = x2 - x1;

			String format = "onFling! (%f,%f) -> (%f, %f). fxsens=%f, fysens=%f";
			Log.v(TAG, String.format(format, x1, y1, x2, y2, fxsens, fysens));

			if (Math.abs(fysens) < 20) { // line, can turn!
				if (fxsens > 0) {
					// left side
					sendRequest("/spinning/left_on?count=1");
				} else {
					// right side
					sendRequest("/spinning/right_on?count=1");
				}
			}

			return true;
		}

	}

	/**
	 * Gesture listener to handle eyes: leds on/off and eyes open/close
	 * 
	 * $Date: 2009-12-30 15:09:35 +0000 (Wed, 30 Dec 2009) $
	 * 
	 * @author $Author: kokotchy $
	 * @version $Revision: 18 $
	 * 
	 */
	class MyGestureEyesListener extends GestureDetector.SimpleOnGestureListener {

		/**
		 * TAG used when debugging
		 */
		private static final String TAG = "MyGestureEyesListener";

		/**
		 * ImageView of the current eye
		 */
		private ImageView mEye;

		/**
		 * Name of the side
		 */
		private String mSideName;

		/**
		 * Create a new Gesture Listener with the given ImageView and the name
		 * of the side
		 * 
		 * @param eye
		 *            ImageView representing the current eye
		 * @param sideName
		 *            Name of the current eye
		 */
		public MyGestureEyesListener(ImageView eye, String sideName) {
			Log.v(TAG, "Constructor!");
			mEye = eye;
			mSideName = sideName;
		}

		@Override
		public boolean onDown(MotionEvent e) {
			// Log.v(TAG, "x: " + e.getX());
			return true;
		}

		@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
				float velocityY) {
			float direction = e2.getY() - e1.getY();
			if (direction < 0) {
				sendRequest("/eyes/open?");
			} else {
				sendRequest("/eyes/close?");
			}
			return true;
		}

		@Override
		public boolean onSingleTapConfirmed(MotionEvent e) {
			if (mSideName.equals(TuxConsts.LEFT_LED_STATE_NAME)) {
				toggleLeftLed();
				return true;
			} else if (mSideName.equals(TuxConsts.RIGHT_LED_STATE_NAME)) {
				toggleRightLed();
				return true;
			}
			return false;
		}

		/**
		 * Return true if the eyes are closed, false otherwise
		 * 
		 * @return True if the eyes are closed, false otherwise
		 */
		private boolean eyesClosed() {
			return mEyesState == TuxConsts.EYES_STATE_CLOSE;
		}

		/**
		 * Toggle the left led state
		 */
		private void toggleLeftLed() {
			if (mLeftLedState == TuxConsts.LED_STATE_ON) {
				mLeftLedState = TuxConsts.LED_STATE_OFF;
				if (!eyesClosed()) {
					mEye.setImageResource(R.drawable.lefteyeoff);
				}
				sendRequest("/leds/off?leds=LED_LEFT");
			} else {
				mLeftLedState = TuxConsts.LED_STATE_ON;
				if (!eyesClosed()) {
					mEye.setImageResource(R.drawable.lefteyeon);
				}
				sendRequest("/leds/on?leds=LED_LEFT&intensity=1.");
			}
		}

		/**
		 * Toggle the right led state
		 */
		private void toggleRightLed() {
			if (mRightLedState == TuxConsts.LED_STATE_ON) {
				mRightLedState = TuxConsts.LED_STATE_OFF;
				if (!eyesClosed()) {
					mEye.setImageResource(R.drawable.righteyeoff);
				}
				sendRequest("/leds/off?leds=LED_RIGHT");
			} else {
				mRightLedState = TuxConsts.LED_STATE_ON;
				if (!eyesClosed()) {
					mEye.setImageResource(R.drawable.righteyeon);
				}
				sendRequest("/leds/on?leds=LED_RIGHT&intensity=1.");
			}
		}
	}

	/**
	 * Activity identifier for the attitune
	 */
	private static final int ACTIVITY_ATTITUNE = 2;

	/**
	 * Id for the Archive button in the menu
	 */
	private static final int ARCHIVE_ID = R.id.menu_archive;

	/**
	 * Id for the Attitune button in the menu
	 */
	private static final int ATTITUNE_ID = R.id.menu_attitune;

	/**
	 * Default IP used to connect
	 */
	private static final String DEFAULT_IP = "192.168.1.16";

	/**
	 * Default port used to connect
	 */
	private static final int DEFAULT_PORT = 54321;

	/**
	 * Id for the Settings button in the menu
	 */
	private static final int PREFS_ID = R.id.menu_preferences;

	/**
	 * Activity identifier for the archive
	 */
	protected static final int ACTIVITY_ARCHIVE = 0;

	/**
	 * Activity identifier for the preferences
	 */
	protected static final int ACTIVITY_PREFERENCES = 1;

	/**
	 * TAG used for debugging
	 */
	protected static final String TAG = "TUX";

	/**
	 * TODO Fill it
	 */
	private static final String DEFAULT_LOCUTOR = "Ryan";

	/**
	 * TODO Fill it
	 */
	private static final boolean DEFAULT_CLEAN_MESSAGE = false;

	/**
	 * TODO Fill it
	 */
	private static final boolean DEFAULT_DISPLAY_BATTERY_LEVEL = true;

	/**
	 * TODO Fill it
	 */
	private static final boolean DEFAULT_DISPLAY_LIGHT_LEVEL = false;

	/**
	 * TODO Fill it
	 */
	private static final boolean DEFAULT_DISPLAY_BATTERY_VALUE = false;

	/**
	 * TODO Fill it
	 */
	private static final boolean DEFAULT_DISPLAY_light_VALUE = false;

	/**
	 * GestureDetector for the spinning
	 */
	private GestureDetector mBottomGestureDetector = null;

	/**
	 * Handler used to detect modification of the tux
	 */
	private Handler mBodyHandler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			Bundle data = msg.getData();
			int eyes = data.getInt(TuxConsts.EYES_STATE_NAME);
			if (eyes != 0) {
				updateEyes(eyes);
			}

			int charger = data.getInt(TuxConsts.CHARGER_STATE_NAME);
			if (charger != 0) {
				updateBottom(charger, mSpinningDirection);
			}

			int spinning = data.getInt(TuxConsts.SPINNING_NAME);
			if (spinning != 0) {
				updateBottom(mChargerState, spinning);
			}

			int left_led = data.getInt(TuxConsts.LEFT_LED_STATE_NAME);
			if (left_led != 0) {
				updateLeftLed(left_led);
			}

			int right_led = data.getInt(TuxConsts.RIGHT_LED_STATE_NAME);
			if (right_led != 0) {
				updateRightLed(right_led);
			}

			int mouth = data.getInt(TuxConsts.MOUTH_STATE_NAME);
			if (mouth != 0) {
				updateMouth(mouth);
			}

			int flippers = data.getInt(TuxConsts.FLIPPERS_STATE_NAME);
			if (flippers != 0) {
				updateFlippers(flippers);
			}

			int battery = data.getInt(TuxConsts.BATTERY_LEVEL_NAME);
			if (battery != 0) {
				refreshBatteryLevel(battery);
			}

			int light = data.getInt(TuxConsts.LIGHT_LEVEL_NAME);
			if (light != 0) {
				((ProgressBar) findViewById(R.id.LightLevel))
						.setProgress(light);
				((TextView) findViewById(R.id.LightField)).setText("" + light);
			}
		}

	};

	/**
	 * Status of the eyes
	 */
	private int mEyesState;

	/**
	 * Status of the flippers
	 */
	private int mFlippersState;

	/**
	 * Handler used for testing the connection
	 */
	private Handler mHandler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			boolean connected = msg.getData().getBoolean("connected");
			TextView connectedField = (TextView) findViewById(R.id.ConnectedField);
			ImageView connectionStatus = (ImageView) findViewById(R.id.ivConnectionStatus);
			if (connected) {
				updateBody();

				connectedField.setText(mHost + ":" + mPort);
				connectionStatus.setImageResource(R.drawable.icon_radio_on);

				startTuxStatus();
			} else {
				connectedField.setText("No");
				connectionStatus.setImageResource(R.drawable.icon_radio_off);

				stopTuxStatus();
			}
		}

	};

	/**
	 * Status of the left led
	 */
	private int mLeftLedState;

	/**
	 * Host to connect
	 */
	private String mHost;

	/**
	 * Status of the moth
	 */
	private int mMouthState;

	/**
	 * Port to connect
	 */
	private int mPort;

	/**
	 * Status of the tux
	 */
	private TuxStatus mStatus;

	/**
	 * Status of the right led
	 */
	private int mRightLedState;

	/**
	 * This object
	 */
	protected Tux tux = this;

	/**
	 * GestureDetecture for the left eye
	 */
	private GestureDetector mLeftEyeGestureDetector;

	/**
	 * GestureDetecture for the right eye
	 */
	private GestureDetector mRightEyeGestureDetector;

	/**
	 * State of the bottom (spinning, charging, ...)
	 */
	private int mChargerState;

	/**
	 * Spin Direction of the tux
	 */
	private int mSpinningDirection;

	/**
	 * Locutor for TTS
	 */
	private String mLocutor;

	/**
	 * TODO Fill it
	 */
	private boolean mCleanMessage;

	/**
	 * TODO Fill it
	 */
	private boolean mDisplayBatteryLevel;

	/**
	 * TODO Fill it
	 */
	private boolean mDisplayLightLevel;

	/**
	 * TODO Fill it
	 */
	private boolean mDisplayBatteryValue;

	/**
	 * TODO Fill it
	 */
	private boolean mDisplayLightValue;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		updateServerInformation();
		updateTTSInformation();
		updateDisplayPreferences();

		TuxConnection connection = new TuxConnection(mHandler, mHost, mPort);
		connection.start();

		setTuxInteraction();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		boolean result = super.onCreateOptionsMenu(menu);
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.options_menu, menu);
		return result;
	}

	@Override
	public boolean onMenuItemSelected(int featureId, MenuItem item) {
		switch (item.getItemId()) {
		case PREFS_ID:
			startActivityForResult(this, Preferences.class,
					ACTIVITY_PREFERENCES);
			return true;
		case ARCHIVE_ID:
			startActivityForResult(this, MessagesList.class, ACTIVITY_ARCHIVE);
			return true;
		case ATTITUNE_ID:
			startActivityForResult(this, Attitunes.class, ACTIVITY_ATTITUNE);
			return true;
		}
		return super.onMenuItemSelected(featureId, item);
	}

	/**
	 * Display or not the given layout
	 * 
	 * @param layoutId
	 *            Layout to modify the display
	 * @param display
	 *            Display to set
	 */
	private void displayLayout(int layoutId, boolean display) {
		View view = findViewById(layoutId);
		if (display) {
			view.setVisibility(LinearLayout.VISIBLE);
		} else {
			view.setVisibility(LinearLayout.GONE);
		}
	}

	/**
	 * Update the level of the battery
	 * 
	 * @param level
	 *            Level to set
	 */
	private void refreshBatteryLevel(int batteryLevel) {
		// to have between 0 and 1700
		ProgressBar level = (ProgressBar) findViewById(R.id.BatteryLevel);
		batteryLevel -= 4800;
		Log.i(TAG, "Current battery level: " + batteryLevel);
		level.setProgress(batteryLevel);

		// TODO better view (% for example)
		TextView textView = (TextView) findViewById(R.id.BatteryField);
		textView.setText("" + batteryLevel);
	}

	/**
	 * Send a request to the server. If result is true, return the DOM Document,
	 * otherwise, return null
	 * 
	 * @param request
	 *            Request to send to the server
	 * @param result
	 *            If the result matter
	 * @return If result, the DOM Document, otherwise, null
	 */
	private Document sendRequest(String request, boolean result) {
		try {
			Document document = null;
			// thanks url to remove ? ... adding empty at the end to be sure
			// that the command is executed
			if (request.charAt(request.length() - 1) == '?') {
				request += "empty";
			}
			URL url = new URL(String.format("http://%s:%d%s", mHost, mPort,
					request));
			URLConnection connection = url.openConnection();

			if (result) {
				DocumentBuilderFactory builderFactory = DocumentBuilderFactory
						.newInstance();
				try {
					DocumentBuilder builder = builderFactory
							.newDocumentBuilder();
					document = builder.parse(new InputSource(connection
							.getInputStream()));
				} catch (ParserConfigurationException e) {
					e.printStackTrace();
				} catch (SAXException e) {
					e.printStackTrace();
				}
			} else {
				String requestResult = "";
				String line = "";
				BufferedReader reader = new BufferedReader(
						new InputStreamReader(connection.getInputStream()));
				while ((line = reader.readLine()) != null) {
					requestResult += line;
				}

				Log.d(TAG, requestResult);

			}
			return document;
		} catch (UnknownHostException e) {
			e.printStackTrace();
			return null;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * Send the given message with the given locutor
	 * 
	 * @param locutor
	 *            Locutor for the message
	 * @param message
	 *            Message to say
	 */
	private void sendTTS(String locutor, String message) {
		String command = "/0/tts/speak?text=%s&locutor=%s&pitch=100";
		sendRequest(String
				.format(command, message.replace(" ", "%20"), locutor));
	}

	/**
	 * Define interaction with the tux
	 */
	private void setTuxInteraction() {
		mBottomGestureDetector = new GestureDetector(this,
				new MyGestureBottomListener());

		ImageView rightEye = (ImageView) findViewById(R.id.RightEye);
		ImageView leftEye = (ImageView) findViewById(R.id.LeftEye);

		mLeftEyeGestureDetector = new GestureDetector(this,
				new MyGestureEyesListener(leftEye,
						TuxConsts.LEFT_LED_STATE_NAME));
		mRightEyeGestureDetector = new GestureDetector(this,
				new MyGestureEyesListener(rightEye,
						TuxConsts.RIGHT_LED_STATE_NAME));

		rightEye.setOnTouchListener(new OnTouchListener() {
			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (mRightEyeGestureDetector.onTouchEvent(event)) {
					return true;
				}
				return false;
			}
		});

		leftEye.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (mLeftEyeGestureDetector.onTouchEvent(event)) {
					return true;
				}
				return false;
			}
		});

		ImageView body = (ImageView) findViewById(R.id.Body);
		body.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				if (mFlippersState == TuxConsts.FLIPPERS_STATE_DOWN) {
					((ImageView) findViewById(R.id.Body))
							.setImageResource(R.drawable.flippersup);
					mFlippersState = TuxConsts.FLIPPERS_STATE_UP;
					sendRequest("/0/flippers/up?");
				} else {
					((ImageView) findViewById(R.id.Body))
							.setImageResource(R.drawable.flippersdown);
					mFlippersState = TuxConsts.FLIPPERS_STATE_DOWN;
					sendRequest("/0/flippers/down?");
				}
			}
		});

		ImageView mouth = (ImageView) findViewById(R.id.Mouth);
		mouth.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				if (mMouthState == TuxConsts.MOUTH_STATE_OPEN) {
					((ImageView) findViewById(R.id.Mouth))
							.setImageResource(R.drawable.mouthclosed);
					mMouthState = TuxConsts.MOUTH_STATE_CLOSE;
					sendRequest("/0/mouth/close?");
					LinearLayout ttsLayout = (LinearLayout) findViewById(R.id.TTS);
					ttsLayout.setVisibility(LinearLayout.INVISIBLE);
				} else {
					((ImageView) findViewById(R.id.Mouth))
							.setImageResource(R.drawable.mouthopened);
					mMouthState = TuxConsts.MOUTH_STATE_OPEN;
					sendRequest("/0/mouth/open?");
					LinearLayout ttsLayout = (LinearLayout) findViewById(R.id.TTS);
					ttsLayout.setVisibility(LinearLayout.VISIBLE);
				}
			}
		});

		ImageButton send = (ImageButton) findViewById(R.id.TTSSend);
		send.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				EditText ttsMessage = (EditText) findViewById(R.id.TTSMessage);
				String message = ttsMessage.getText().toString();
				sendTTS(mLocutor, message);
				saveMessage(mLocutor, message);
				if (mCleanMessage) {
					ttsMessage.setText("");
				}
			}
		});

		LinearLayout bottom = (LinearLayout) findViewById(R.id.BottomLayout);
		bottom.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (mBottomGestureDetector.onTouchEvent(event)) {
					Log.v(TAG, "Dispatch for mBottomGestureDetector!");
					return true;
				}
				return false;
			}
		});
	}

	/**
	 * Start the given activity with the requestCode
	 * 
	 * @param context
	 *            Context for the activity
	 * @param cls
	 *            Activity to start
	 * @param requestCode
	 *            Request code of the activity
	 */
	private void startActivityForResult(Context context, Class<?> cls,
			int requestCode) {
		Intent intent = new Intent(context, cls);
		startActivityForResult(intent, requestCode);
	}

	/**
	 * Start the tux status
	 */
	private void startTuxStatus() {
		mStatus = new TuxStatus(mBodyHandler, mHost, mPort);
		mStatus.start();
	}

	/**
	 * Stop the tux status
	 */
	private void stopTuxStatus() {
		if (mStatus != null) {
			mStatus.close();
		}
	}

	/**
	 * Update the view of the tux
	 */
	private void updateBody() {
		updateFlippers();
		updateMouth();
		updateLeds();
		updateEyes();
		updateBottom();
	}

	/**
	 * Update the bottom of the tux
	 */
	private void updateBottom() {
		updateBottom(mChargerState, mSpinningDirection);
	}

	/**
	 * Update the bottom of the tux
	 * 
	 * @param chargerState
	 *            New state of the bottom
	 * @param spinningDirection
	 *            Direction of the spinning (if any)
	 */
	private void updateBottom(int chargerState, int spinningDirection) {
		String format = "Update bottom! bottomState=%d and spinningDirection=%d";
		Log.v(TAG, String.format(format, chargerState, spinningDirection));
		mChargerState = chargerState;
		mSpinningDirection = spinningDirection;
		if (chargerState == TuxConsts.CHARGER_CHARGING
				|| chargerState == TuxConsts.CHARGER_TRICKLE) {
			((ImageView) findViewById(R.id.Bottom))
					.setImageResource(R.drawable.spincharging);
			Log.v(TAG, "Charging");
		} else {
			int imgId = 0;
			switch (spinningDirection) {
			case TuxConsts.SPIN_LEFT:
				imgId = R.drawable.spinleft;
				break;
			case TuxConsts.SPIN_RIGHT:
				imgId = R.drawable.spinright;
				break;
			case TuxConsts.SPIN_NONE:
			default:
				imgId = R.drawable.spinoff;
			}
			((ImageView) findViewById(R.id.Bottom)).setImageResource(imgId);
			Log.v(TAG, "Discharging");
		}
	}

	/**
	 * Update the preference about display
	 */
	private void updateDisplayPreferences() {
		SharedPreferences preferences = PreferenceManager
				.getDefaultSharedPreferences(this);
		mDisplayBatteryLevel = preferences.getBoolean(
				"display_battery_level_preference",
				DEFAULT_DISPLAY_BATTERY_LEVEL);
		mDisplayBatteryValue = preferences.getBoolean("display_battery_value",
				DEFAULT_DISPLAY_BATTERY_VALUE);

		mDisplayLightLevel = preferences.getBoolean(
				"display_light_level_preference", DEFAULT_DISPLAY_LIGHT_LEVEL);
		mDisplayLightValue = preferences.getBoolean("display_light_value",
				DEFAULT_DISPLAY_light_VALUE);

		String format = "Update display: battery=%b (value=%b), light=%b (value=%b)";
		Log.v(TAG, String.format(format, mDisplayBatteryLevel,
				mDisplayBatteryValue, mDisplayLightLevel, mDisplayLightValue));

		displayLayout(R.id.BatteryLayout, mDisplayBatteryLevel);
		displayLayout(R.id.BatteryField, mDisplayBatteryValue);

		displayLayout(R.id.LightLayout, mDisplayLightLevel);
		displayLayout(R.id.LightField, mDisplayLightValue);
	}

	/**
	 * Update the view of the eyes of the tux
	 */
	private void updateEyes() {
		updateEyes(mEyesState);
	}

	/**
	 * Update the view of the eyes with the given position
	 * 
	 * @param eyes
	 *            Position of the eyes
	 */
	private void updateEyes(int eyes) {
		mEyesState = eyes;
		if (eyes == TuxConsts.EYES_STATE_CLOSE) {
			((ImageView) findViewById(R.id.RightEye))
					.setImageResource(R.drawable.righteyeclosed);
			((ImageView) findViewById(R.id.LeftEye))
					.setImageResource(R.drawable.lefteyeclosed);
		} else {
			updateLeds();
		}
	}

	/**
	 * Update the view of the flippers of the tux
	 */
	private void updateFlippers() {
		updateFlippers(mFlippersState);
	}

	/**
	 * Update the view of the flippers with the given value
	 * 
	 * @param value
	 *            Position of the flippers
	 */
	private void updateFlippers(int value) {
		mFlippersState = value;
		if (value == TuxConsts.FLIPPERS_STATE_DOWN) {
			((ImageView) findViewById(R.id.Body))
					.setImageResource(R.drawable.flippersdown);
		} else {
			((ImageView) findViewById(R.id.Body))
					.setImageResource(R.drawable.flippersup);
		}
	}

	/**
	 * Update the view of the leds of the tux
	 */
	private void updateLeds() {
		updateRightLed(mRightLedState);
		updateLeftLed(mLeftLedState);
	}

	/**
	 * Update the view of the left led
	 * 
	 * @param value
	 *            State of the left led
	 */
	private void updateLeftLed(int value) {
		mLeftLedState = value;
		if (value == TuxConsts.LED_STATE_OFF) {
			((ImageView) findViewById(R.id.LeftEye))
					.setImageResource(R.drawable.lefteyeoff);
		} else {
			((ImageView) findViewById(R.id.LeftEye))
					.setImageResource(R.drawable.lefteyeon);
		}
	}

	/**
	 * Update the view of the mouth of the tux
	 */
	private void updateMouth() {
		updateMouth(mMouthState);
	}

	/**
	 * Update the view of the mouth with the given position
	 * 
	 * @param value
	 *            Position of the mouth
	 */
	private void updateMouth(int value) {
		mMouthState = value;
		if (value == TuxConsts.MOUTH_STATE_OPEN) {
			((ImageView) findViewById(R.id.Mouth))
					.setImageResource(R.drawable.mouthopened);
			LinearLayout ttsLayout = (LinearLayout) findViewById(R.id.TTS);
			ttsLayout.setVisibility(LinearLayout.VISIBLE);
		} else {
			((ImageView) findViewById(R.id.Mouth))
					.setImageResource(R.drawable.mouthclosed);
			LinearLayout ttsLayout = (LinearLayout) findViewById(R.id.TTS);
			ttsLayout.setVisibility(LinearLayout.GONE);
		}
	}

	/**
	 * Update the right led with the given state
	 * 
	 * @param value
	 *            State of the right led
	 */
	private void updateRightLed(int value) {
		mRightLedState = value;
		if (value == TuxConsts.LED_STATE_OFF) {
			((ImageView) findViewById(R.id.RightEye))
					.setImageResource(R.drawable.righteyeoff);
		} else {
			((ImageView) findViewById(R.id.RightEye))
					.setImageResource(R.drawable.righteyeon);
		}
	}

	/**
	 * Update host and port value from preferences
	 */
	private void updateServerInformation() {
		SharedPreferences preferences = PreferenceManager
				.getDefaultSharedPreferences(this);
		mHost = preferences.getString("ip_server_preference", DEFAULT_IP);
		mPort = preferences.getInt("port_server", DEFAULT_PORT);
		String format = "updateServerInformation! Connection to %s:%d";
		Log.v(TAG, String.format(format, mHost, mPort));
	}

	/**
	 * Update information about TTS
	 */
	private void updateTTSInformation() {
		SharedPreferences preferences = PreferenceManager
				.getDefaultSharedPreferences(this);
		mLocutor = preferences.getString("locutor_tts_preference",
				DEFAULT_LOCUTOR);
		mCleanMessage = preferences.getBoolean("clean_tts_preference",
				DEFAULT_CLEAN_MESSAGE);
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		switch (requestCode) {
		case ACTIVITY_ATTITUNE:
			if (data != null) {
				Bundle extras = data.getExtras();
				int type = extras.getInt("type");
				Log.i(TAG, "Type of attitune: " + type);
				switch (type) {
				case Attitune.ATTITUNE_URL:
					String url = extras.getString("url");
					Log.i(TAG, "Load attitune from this url: " + url);
					sendRequest("/0/attitune/load_and_play?path="
							+ url.replaceAll(" ", "%20"));
					break;
				default:
				case Attitune.ATTITUNE_FILE:
					String attituneName = extras.getString("attituneName");
					if (attituneName != null) {
						Log.i(TAG, "Try to play " + attituneName);
						String pattern = "/0/attitune_manager/start_attitune_by_name?begin=%f&name=%s";
						sendRequest(String.format(pattern, 0.0, attituneName
								.replace(" ", "%20")));

					}
				}
			}
			break;
		case ACTIVITY_ARCHIVE:
			if (data != null) {
				Uri uri = data.getData();
				Cursor query = managedQuery(uri, new String[] {
						Messages.MESSAGE, Messages.LOCUTOR }, null, null, null);
				int msgColumn = query.getColumnIndex(Messages.MESSAGE);
				int locColumn = query.getColumnIndex(Messages.LOCUTOR);
				query.moveToFirst();
				String message = query.getString(msgColumn);
				String locutor = query.getString(locColumn);
				sendTTS(locutor, message);
			}
			break;
		case ACTIVITY_PREFERENCES:
			updateServerInformation();
			updateTTSInformation();
			updateDisplayPreferences();
			TuxConnection connection = new TuxConnection(mHandler, mHost, mPort);
			connection.start();
			break;
		}
	}

	/**
	 * Save the message
	 * 
	 * @param locutor
	 *            Locutor used when saying the message
	 * @param message
	 *            Message to say
	 */
	protected void saveMessage(String locutor, String message) {
		ContentValues values = new ContentValues();
		values.put(MessageList.Messages.LOCUTOR, locutor);
		values.put(MessageList.Messages.MESSAGE, message);
		Log.v(TAG, "Insert into ContentProvider");
		getContentResolver().insert(MessageList.Messages.CONTENT_URI, values);
	}

	/**
	 * Send a request to the server without any result
	 * 
	 * @param request
	 *            Request to send
	 */
	protected void sendRequest(String request) {
		sendRequest(request, false);
	}
}
